package com.jerry.controller;

import com.jerry.BO.FileChunkMeta;
import com.jerry.BO.MetaFile;
import com.jerry.DTO.FileMeta;
import com.jerry.VO.MetaFileVO;
import com.jerry.errors.BusinessException;
import com.jerry.errors.EnumException;
import com.jerry.response.CommonResponse;
import com.jerry.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@Slf4j
@RestController
@RequestMapping("/")
public class FileController  {
    private final FileService fileService;
    private final ReentrantReadWriteLock reentrantReadWriteLock;
    public FileController(FileService fileService, ReentrantReadWriteLock reentrantReadWriteLock) {
        this.fileService = fileService;
        this.reentrantReadWriteLock = reentrantReadWriteLock;
    }

    @PostMapping("/upload")
    public CommonResponse upload(@RequestParam("bucketName") String bucketName,
                                 @RequestParam("file") MultipartFile file,
                                 @RequestParam("nickName") String nickName,
                                 @RequestParam("fileType") String fileType) throws IOException {
        String fileUrl = fileService.upload(bucketName,file,nickName,fileType);
        return CommonResponse.success(fileUrl);
    }

    @PostMapping("/meta")
    public CommonResponse meta(@RequestBody FileMeta fileMeta) {
        MetaFileVO metaFileVO = fileService.meta(fileMeta);
        return CommonResponse.success(metaFileVO);
    }

    @PostMapping("/chunk/upload")
    public CommonResponse chunkUpload(@RequestParam("bucketName") String bucketName,
                                      @RequestParam("filename") String filename,
                                      @RequestParam("md5") String md5,
                                      @RequestParam("chunkNo") Integer chunkNo,
                                      @RequestParam("file") MultipartFile file) {
        String fileMd5 = fileService.uploadChunk(bucketName, filename, md5, chunkNo, file);
        return CommonResponse.success(fileMd5);
    }
    @DeleteMapping("{bucketName}/{fileName}")
    public CommonResponse delete(@PathVariable String bucketName,
                                 @PathVariable String fileName){
        fileService.delete(bucketName,fileName);
        return CommonResponse.success();
    }
    @GetMapping("{bucketName}/{fileName}")
    public void download(HttpServletResponse response,
                         @PathVariable String bucketName,
                         @PathVariable String fileName) throws IOException {
        MetaFile metaFile = fileService.getMeta(bucketName, fileName);
        response.reset();
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("UTF-8");
        // 注意：如果文件大小未知，可以省略setContentLength
        // response.setContentLength(metaFile.getFileSize().intValue());
        response.setHeader("Content-Disposition", "attachment;filename=\"" +
                metaFile.getFileName() + "." + metaFile.getExtension() + "\"");

        try (ServletOutputStream outputStream = response.getOutputStream()) {
            for (FileChunkMeta chunk : metaFile.getFileChunkMetas()) {
                byte[] content = fileService.downloadChunk(chunk);
                outputStream.write(content);
                // 如果需要，可以在这里刷新输出流
                // outputStream.flush();
            }
            // 完成后确保刷新输出流
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
            // 设置适当的HTTP状态码和错误消息
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            // 你可以考虑将错误信息写入响应体，但通常对于下载请求，我们只需要状态码
            // 抛出异常到上层处理，或者返回一个自定义的错误响应体
            throw new BusinessException(EnumException.FALE_TO_DOWNLOAD_FILE);
        }
    }
  /* @GetMapping("{bucketName}/{fileName}")
   public void download(HttpServletResponse response,
                        @PathVariable String bucketName,
                        @PathVariable String fileName) throws FileNotFoundException {
       MetaFile metaFile = fileService.getMeta(bucketName, fileName);
       List<FileChunkMeta> chunks = metaFile.getFileChunkMetas();
       *//*response.reset();*//*
       response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        *//*response.setCharacterEncoding("utf-8");
        response.setContentLength(metaFile.getFileSize().intValue());*//*
       response.setHeader("Content-Disposition", "attachment;filename=" +
               metaFile.getFileName() + metaFile.getExtension());
       File file = new File("empty.mp4"); // 替换为你想要创建的文件名和路径
       if (file.exists()){
           file.delete();
       }
       try {
           if (file.createNewFile()) {
               System.out.println("文件创建成功!");
           }
       } catch (IOException e) {
           e.printStackTrace();
           System.out.println("文件创建失败!");
       }
       FileOutputStream Stream = new FileOutputStream(file);
       for (FileChunkMeta chunk : chunks) {
           byte[] content = fileService.downloadChunk(chunk);
           try {
               Stream.write(content);
           } catch (IOException e) {
               e.printStackTrace();
               throw new BusinessException(EnumException.FALE_TO_DOWNLOAD_FILE);
           }
       }
       try (InputStream inputStream = new FileInputStream(file)) {
           // 将文件内容写入响应输出流
           byte[] buffer = new byte[1024];
           int bytesRead;
           while ((bytesRead = inputStream.read(buffer)) != -1) {
               response.getOutputStream().write(buffer, 0, bytesRead);
           }
           response.flushBuffer(); // 确保所有数据都被写出
       } catch (IOException e) {
           e.printStackTrace();
       }
   }*/

    /*@GetMapping("/play/{bucketName}/{fileName}")
    public DeferredResult<ResponseEntity<Resource>> play( @PathVariable String bucketName,  @PathVariable String fileName, HttpServletResponse response) {
        DeferredResult<ResponseEntity<Resource>> deferredResult = new DeferredResult<>();

        new Thread(() -> {
            try {
                MetaFile metaFile = fileService.getMeta(bucketName, fileName);
                List<FileChunkMeta> chunks = metaFile.getFileChunkMetas();

                // 设置响应头信息
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

                // 使用ServletOutputStream来直接写入响应
                try (OutputStream outputStream = response.getOutputStream()) {
                    for (FileChunkMeta chunk : chunks) {
                        // 下载当前片段
                        byte[] content = fileService.downloadChunk(chunk);

                        // 将当前片段写入到响应输出流中
                        outputStream.write(content);
                        outputStream.flush(); // 确保数据被写出
                    }
                }

                // 设置成功状态码
                response.setStatus(HttpServletResponse.SC_OK);

                // 完成后，设置DeferredResult的结果
                deferredResult.setResult(ResponseEntity.ok().build());
            } catch (IOException e) {
                e.printStackTrace();
                // 设置错误状态码
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

                // 完成后，设置DeferredResult的错误结果
                deferredResult.setErrorResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
            }
        }).start();

        return deferredResult;
    }*/
    /*@GetMapping("/play/{bucketName}/{fileName}")
    public void play(HttpServletResponse response,
                                         @PathVariable String bucketName,
                                         @PathVariable String fileName) {
        MetaFile metaFile = fileService.getMeta(bucketName, fileName);
        List<FileChunkMeta> chunks = metaFile.getFileChunkMetas();
        List<InputStream> inputStreamList = new ArrayList<>();
        for (FileChunkMeta chunk : chunks) {
            String chunkPath = fileService.downloadChunk(chunk);
            try{
                reentrantReadWriteLock.readLock().lock();
                File file = new File(chunkPath);
                inputStreamList.add(new FileInputStream(file));
            }catch (Exception e){
                throw new RuntimeException("获取文件失败");
            }finally {
                reentrantReadWriteLock.readLock().unlock();
            }
        }
        *//*Enumeration<InputStream> enumeration = Collections.enumeration(inputStreamList);
        SequenceInputStream sequenceInputStream = new SequenceInputStream(enumeration);*//*
        // 设置响应头
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 使用APPLICATION_OCTET_STREAM
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        try {
            // 将文件内容写入响应输出流
            byte[] buffer = new byte[1024];
            int bytesRead;
            for (InputStream inputStream : inputStreamList){
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    response.getOutputStream().write(buffer, 0, bytesRead);
                    response.flushBuffer();
                }
            }
             // 确保所有数据都被写出
        } catch (IOException e) {
            e.printStackTrace();
        }
    }*/

}
